#ifndef __mutex_H__
#define __mutex_H__

#include <thread>
#include <memory>
#include <functional>
#include <pthread.h>
#include <stdint.h>
#include <semaphore.h>
#include <atomic>

#include "noncopyable.h"


/*
Semaphore       信号量

ScopedLockImpl  局部锁的模板实现
Mutex           互斥量

RWMutex             读写互斥量
WriteScopedLockImpl 局部写锁
ReadScopedLockImpl  局部读锁

Spinlock    自旋锁
*/



namespace framework
{

//信号量
class Semaphore: Noncopyable
{
public:
    Semaphore(uint32_t count = 0);
    ~Semaphore();

    //获取信号量
    void wait();

    //释放信号量
    void notify();
private:
    sem_t m_semaphore; //信号量
};



//局部锁的模板实现
template<class T>
struct ScopedLockImpl
{
public:
    //构造函数自动上锁
    ScopedLockImpl(T& mutex):m_mutex(mutex)
    {
        m_mutex.lock();
        m_locked = true;
    }

    //析构函数自动解锁
    ~ScopedLockImpl()
    {
        unlock();
    }

    //加锁
    void lock()
    {
        if(!m_locked)
        {
            m_mutex.lock();
            m_locked = true;
        }
    }

    //解锁
    void unlock()
    {
        if(m_locked)
        {
            m_mutex.unlock();
            m_locked = false;
        }
    }

private:
    T& m_mutex;     //锁
    bool m_locked;  //是否已上锁
};


//互斥量
class Mutex: Noncopyable
{
public:
    //局部锁
    using Lock = ScopedLockImpl<Mutex>;

    Mutex()
    {
        pthread_mutex_init(&m_mutex, nullptr);
    }

    ~Mutex()
    {
        pthread_mutex_destroy(&m_mutex);
    }

    void lock()
    {
        pthread_mutex_lock(&m_mutex);
    }

    void unlock()
    {
        pthread_mutex_unlock(&m_mutex);
    }

private:
    pthread_mutex_t m_mutex;
};




//局部读锁模板实现
template<class T>
struct ReadScopedLockImpl 
{
public:
    //构造自动加锁
    ReadScopedLockImpl(T& mutex)
        :m_mutex(mutex) {
        m_mutex.rdlock();
        m_locked = true;
    }

    //析构自动解锁
    ~ReadScopedLockImpl() {
        unlock();
    }

    //上读锁
    void lock() {
        if(!m_locked) {
            m_mutex.rdlock();
            m_locked = true;
        }
    }

    //解读锁
    void unlock() {
        if(m_locked) {
            m_mutex.unlock();
            m_locked = false;
        }
    }
private:
    T& m_mutex;     // mutex
    bool m_locked;  // 是否已上锁
};


//局部写锁模板实现
template<class T>
struct WriteScopedLockImpl {
public:
    //构造自动加锁
    WriteScopedLockImpl(T& mutex)
        :m_mutex(mutex) {
        m_mutex.wrlock();
        m_locked = true;
    }

    //析构自动解锁
    ~WriteScopedLockImpl() {
        unlock();
    }

    //上写锁
    void lock() 
    {
        if(!m_locked) 
        {
            m_mutex.wrlock();
            m_locked = true;
        }
    }

    //解写锁
    void unlock() 
    {
        if(m_locked) 
        {
            m_mutex.unlock();
            m_locked = false;
        }
    }
private:
    T& m_mutex;     // Mutex
    bool m_locked;  // 是否已上锁
};

//读写互斥量
class RWMutex: Noncopyable
{
public:

    // 局部读锁
    using ReadLock = ReadScopedLockImpl<RWMutex>;

    // 局部写锁
    using WriteLock = WriteScopedLockImpl<RWMutex>;

    RWMutex()
    {
        //参数2设置锁的属性
        pthread_rwlock_init(&m_lock, nullptr);
    }

    ~RWMutex()
    {
        pthread_rwlock_destroy(&m_lock);
    }

    //上读锁
    void rdlock()
    {
        pthread_rwlock_rdlock(&m_lock);
    }

    //上写锁
    void wrlock()
    {
        pthread_rwlock_wrlock(&m_lock);
    }

    //解锁
    void unlock()
    {
        pthread_rwlock_unlock(&m_lock);
    }

private:
    pthread_rwlock_t m_lock;    //读写锁
};


//自旋锁
/*
互斥量使用阻塞等待方式，即当线程请求一个被其他线程占用的互斥量时，线程会被阻塞，直到该互斥量被释放；
自旋锁使用忙等待方式，即当线程请求一个被其他线程占用的自旋锁时，线程会一直自旋等待，直到该自旋锁被释放(系统肯能会优化，如长时间拿不到锁线程会进入内核态)
如果对于锁的持有时间比较短，同时需要高效的线程同步方式，可以使用自旋锁；
如果对于锁的持有时间比较长，同时需要避免不必要的CPU消耗，可以使用互斥量
*/
class Spinlock: Noncopyable
{
public:
    //局部锁
    using Lock = ScopedLockImpl<Spinlock>;

    //构造函数
    Spinlock() {
        pthread_spin_init(&m_mutex, 0);
    }

    //析构函数
    ~Spinlock() {
        pthread_spin_destroy(&m_mutex);
    }

    //上锁
    void lock() {
        pthread_spin_lock(&m_mutex);
    }

    //解锁
    void unlock() {
        pthread_spin_unlock(&m_mutex);
    }
private:
    pthread_spinlock_t m_mutex; // 自旋锁
};



//原子锁
//和自旋锁概念一样，但系统不会优化这个锁，所以线程不会进入内核态
class CASLock: Noncopyable
{
public:
    using Lock = ScopedLockImpl<CASLock>;

    CASLock()
    {
        m_mutex.clear();
    }
    ~CASLock() {}

    //上锁
    void lock()
    {
        /*
        是C++11中的一个函数模板，用于将一个std::atomic_flag对象设置为已设置状态，并返回设置前的值

        并且可以控制在什么顺序下对内存的读写操作进行同步：
        （1）memory_order_relaxed：不强制同步，不对其他线程可见，仅保证当前线程中的内存读写顺序。这是最轻量级的同步方式，
        因为它不需要任何同步操作，所以在高并发场景下性能很高。但是，由于没有同步操作，所以可能导致多线程中的数据竞争和不一致。
        （2）memory_order_acquire：强制对其他线程的内存操作立即对当前线程可见。这个内存顺序确保了当前线程对内存的读取操作在该操作后，
        可以读取到其他线程在该操作之前对该内存的写入操作的值。该顺序主要用于实现读取锁，防止读取操作与写入操作重叠，导致读取到不一致的数据。
        （3）memory_order_release：强制将当前线程的内存操作立即对其他线程可见。这个内存顺序确保了当前线程对内存的写入操作在该操作后，
        可以被其他线程读取到。该顺序主要用于实现写入锁，防止写入操作与读取操作重叠，导致其他线程读取到不一致的数据。
        （4）memory_order_acq_rel：同时包含了memory_order_acquire和memory_order_release的语义，既保证了写入操作对其他线程的可见性，也保证了读取操作能够读取到其他线程的写入操作的值。
        （5）memory_order_seq_cst：全序同步，即强制执行所有内存操作的顺序与所有线程看到的顺序一致。这是最强大的同步方式，可以保证数据的强一致性，
        但是也是最慢的同步方式，因为需要等待所有线程都完成同步操作才能进行下一步操作。
        */

        while(std::atomic_flag_test_and_set_explicit(&m_mutex, std::memory_order_acquire));
    }

    //解锁
    void unlock()
    {
        /*
        用于将一个 std::atomic_flag 对象的值设置为 false
        */
        std::atomic_flag_clear_explicit(&m_mutex, std::memory_order_release);
    }

private:
    /*
    volatile:
    1.编译器为了提高程序的运行效率，会对一些变量进行优化，如将变量缓存在寄存器中。但是，如果变量被标记为volatile，编译器就会避免这种优化
    2.提示编译器该变量可能会在未知的时间被修改，因此需要从内存中读取。在多线程或多进程的环境中，该变量可能会被其他线程或进程修改，因此需要使用volatile关键字来确保读取到的是最新的值。

    atomic_flag:
    是C++11中的原子类型，表示一个简单的布尔标志。它被设计为一种快速的同步原语，用于保护共享资源的访问。std::atomic_flag类型的对象只有两种状态，分别为“已设置”和“未设置”。
    clear()：将std::atomic_flag对象设置为未设置状态。
    test_and_set()：将std::atomic_flag对象设置为已设置状态，并返回设置前的值。
    flag.test_and_set(std::memory_order_acquire)：将std::atomic_flag对象设置为已设置状态，并在此操作之前保证所有之前的读写操作都已经完成。
    */
    volatile std::atomic_flag m_mutex; //原子状态
};



//空锁，用于测试
class NullMutex: Noncopyable
{
public:
    //局部锁
    using Lock = ScopedLockImpl<NullMutex>;

    NullMutex() {}
    ~NullMutex() {}

    void lock() {}
    void unlock() {}
};

//空读写锁，用于测试
class NullRWMutex: Noncopyable
{
    using ReadLock = ReadScopedLockImpl<NullRWMutex>;
    using WriteLock = WriteScopedLockImpl<NullRWMutex>;

    NullRWMutex() {}
    ~NullRWMutex() {}

    void rdlock() {}
    void wdlock() {}
    void unlock() {}
};



}







#endif
